home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / os2 / souper15.zip / SMTP.C < prev    next >
C/C++ Source or Header  |  1996-05-18  |  7KB  |  331 lines

  1. /* $Id: smtp.c 1.1 1996/05/18 21:13:41 cthuang Exp $
  2.  *
  3.  * Send mail reply packet using SMTP directly
  4.  */
  5. #include <ctype.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <netdb.h>
  13. #ifdef __WIN32__
  14. #include <winsock.h>
  15. #else
  16. #include <unistd.h>
  17. #endif
  18. #include "socket.h"
  19. #include "souper.h"
  20.  
  21. extern char *mailGateway;
  22.  
  23. /* Close SMTP connection and socket */
  24.  
  25. void
  26. smtpClose (int socket)
  27. {
  28.     SockPuts(socket, "QUIT");
  29.     SockClose(socket);
  30. }
  31.  
  32. /* Get a response from the SMTP server and test it
  33. */
  34. static int
  35. getSmtpReply (int socket, char *response)
  36. {
  37.     char buf[BUFSIZ];
  38.  
  39.     do {
  40.     SockGets(socket, buf, BUFSIZ);
  41.     } while (buf[3] == '-');        /* wait until not a continuation */
  42.  
  43.     if (strncmp(buf, response, 3) != 0) {
  44.     fprintf(stderr, "Expecting SMTP %s reply, got %s\n", response, buf);
  45.     }
  46.     return (buf[0] == *response);    /* only first digit really matters */
  47. }
  48.  
  49. /* Open socket and intialize connection to SMTP server. */
  50.  
  51. #ifdef DEBUG
  52. int
  53. smtpConnect (void)
  54. {
  55.     return 1;
  56. }
  57. #else
  58. int
  59. smtpConnect (void)
  60. {
  61.     struct servent *sp;
  62.     int    socket;
  63.     struct sockaddr_in local;
  64.     int addrLen;
  65.     struct hostent *hp;
  66.     const char *fromHost;
  67.  
  68.     if ((sp = getservbyname("smtp", "tcp")) == NULL) {
  69.     fprintf(stderr, "smtp/tcp: Unknown service.\n");
  70.     return -1;
  71.     }
  72.  
  73.     if ((socket = Socket(mailGateway, ntohs(sp->s_port))) < 0) {
  74.     fprintf(stderr, "Cannot connect to mail server %s\n", mailGateway);
  75.     return -1;
  76.     }
  77.  
  78.     if (!getSmtpReply(socket, "220")) {
  79.     printf("Disconnecting from %s\n", mailGateway);
  80.     smtpClose(socket);
  81.     return -1;
  82.     }
  83.  
  84.     addrLen = sizeof(local);
  85.     getsockname(socket, (struct sockaddr *)&local, &addrLen);
  86.     hp = gethostbyaddr((const char *)&local.sin_addr, sizeof(local.sin_addr),
  87.     AF_INET);
  88.     fromHost = hp ? hp->h_name : inet_ntoa(local.sin_addr);
  89.     SockPrintf(socket, "HELO %s\r\n", fromHost);
  90.     if (!getSmtpReply(socket, "250")) {
  91.     printf("Disconnecting from %s\n", mailGateway);
  92.     smtpClose(socket);
  93.     return -1;
  94.     }
  95.     return socket;
  96. }
  97. #endif
  98.  
  99. /* Extract mail address from the string.
  100.  * Return a pointer to a static buffer containing the address or
  101.  * NULL on an error.
  102.  */
  103. static const char *
  104. extractAddress (const char *src)
  105. {
  106.     static char buf[BUFSIZ];
  107.     char ch, *put;
  108.     const char *get;
  109.     char gotAddress;
  110.  
  111.     gotAddress = 0;
  112.     put = buf;
  113.     if ((get = strchr(src, '<')) != 0) {
  114.     char ch = *++get;
  115.     while (ch != '>' && ch != '\0') {
  116.         *put++ = ch;
  117.         ch = *++get;
  118.     }
  119.     gotAddress = 1;
  120.     } else {
  121.     get = src;
  122.     ch = *get++;
  123.  
  124.     /* Skip leading whitespace. */
  125.     while (ch != '\0' && isspace(ch))
  126.         ch = *get++;
  127.  
  128.     while (ch != '\0') {
  129.         if (isspace(ch)) {
  130.         ch = *get++;
  131.  
  132.         } else if (ch == '(') {
  133.         /* Skip comment. */
  134.         int nest = 1;
  135.         while (nest > 0 && ch != '\0') {
  136.             ch = *get++;
  137.  
  138.             if (ch == '(')
  139.             ++nest;
  140.             else if (ch == ')')
  141.             --nest;
  142.         }
  143.  
  144.         if (ch == ')') {
  145.             ch = *get++;
  146.         }
  147.  
  148.         } else if (ch == '"') {
  149.         /* Copy quoted string. */
  150.         do {
  151.             *put++ = ch;
  152.             ch = *get++;
  153.         } while (ch != '"' && ch != '\0');
  154.  
  155.         if (ch == '"') {
  156.             *put++ = ch;
  157.             ch = *get++;
  158.         }
  159.  
  160.         } else {
  161.         /* Copy address. */
  162.         while (ch != '\0' && ch != '(' && !isspace(ch)) {
  163.             *put++ = ch;
  164.             ch = *get++;
  165.         }
  166.         gotAddress = 1;
  167.         }
  168.     }
  169.     }
  170.  
  171.     if (gotAddress) {
  172.     *put = '\0';
  173.     return buf;
  174.     } else {
  175.     return NULL;
  176.     }
  177. }
  178.  
  179. /* Search for ',' separating addresses.
  180. */
  181. static char *
  182. findAddressSep (char *src)
  183. {
  184.     char ch, matchCh;
  185.  
  186.     ch = *src; 
  187.     while (ch != '\0' && ch != ',') {
  188.         if (ch == '"') {
  189.             matchCh = '"';
  190.         } else if (ch == '(') {
  191.             matchCh = ')';
  192.         } else if (ch == '<') {
  193.             matchCh = '>';
  194.         } else {
  195.             matchCh = '\0';
  196.         }
  197.  
  198.         if (matchCh) {
  199.             do {
  200.                 ch = *(++src);
  201.             } while (ch != '\0' && ch != matchCh);
  202.  
  203.             if (ch == '\0')
  204.                 break;
  205.         }
  206.         ch = *(++src);
  207.     }
  208.  
  209.     return src;
  210. }
  211.     
  212. /* Send RCPT command.
  213. */
  214. static void
  215. sendSmtpRcpt (int socket, const char *buf)
  216. {
  217.     printf("%s: mailing to %s\n", progname, buf);
  218.     SockPrintf(socket, "RCPT TO:<%s>\r\n", buf);
  219.     getSmtpReply(socket, "250");
  220. }
  221.  
  222. /* Send an RCPT command for each address in the address list.
  223. */
  224. static void
  225. putAddresses (int socket, char *addresses)
  226. {
  227.     char *srcEnd, *startAddr, *endAddr, saveCh;
  228.     const char *addr;
  229.     
  230.     srcEnd = strchr(addresses, '\0');
  231.     startAddr = addresses;
  232.  
  233.     while (startAddr < srcEnd) {
  234.     endAddr = findAddressSep(startAddr);
  235.     saveCh = *endAddr;
  236.     *endAddr = '\0';
  237.     addr = extractAddress(startAddr);
  238.     if (addr) {
  239.         sendSmtpRcpt(socket, addr);
  240.     }
  241.     *endAddr = saveCh;
  242.     startAddr = endAddr + 1;
  243.     }
  244. }
  245.  
  246. /* Send message to SMTP server.  Return TRUE if successful.
  247.  */
  248. int
  249. smtpMail (int socket, FILE *fd, size_t bytes)
  250. {
  251.     const char *addr;
  252.     char buf[BUFSIZ], *addrs, ch;
  253.     char *from, *resentTo, *s;
  254.     char more;
  255.     long offset;
  256.     size_t count;
  257.  
  258.     /* Look for From header and send MAIL command to SMTP server. */
  259.     from = getHeader(fd, "From");
  260.     if (from == NULL || (addr = extractAddress(from)) == NULL) {
  261.     puts("No address in From header");
  262.     return 0;
  263.     }
  264.     printf("%s: mailing from %s\n", progname, addr);
  265.     SockPrintf(socket, "MAIL FROM:<%s>\r\n", addr);
  266.     free(from);
  267.     if (!getSmtpReply(socket, "250")) {
  268.     return 0;
  269.     }
  270.  
  271.     offset = ftell(fd);
  272.     if ((resentTo = getHeader(fd, "Resent-To")) != NULL) {
  273.     /* Send to address on Resent-To header. */
  274.     putAddresses(socket, resentTo);
  275.     free(resentTo);
  276.     } else {
  277.     /* Send to addresses on To, Cc and Bcc headers. */
  278.     more = fgets(buf, sizeof(buf), fd) != 0;
  279.     while (more) {
  280.         if (buf[0] == '\n')
  281.         break;
  282.  
  283.         if (isHeader(buf, "To", 2) || isHeader(buf, "Cc", 2)
  284.          || isHeader(buf, "Bcc", 3))
  285.         {
  286.         addrs = buf;
  287.         while (*addrs != '\0' && !isspace(*addrs)) {
  288.             ++addrs;
  289.         }
  290.         putAddresses(socket, addrs);
  291.  
  292.         /* Read next line and check if it is a continuation line. */
  293.         while ((more = fgets(buf, sizeof(buf), fd) != 0) != 0) {
  294.             ch = buf[0];
  295.             if (ch == '\n' || (ch != ' ' && ch != '\t'))
  296.             break;
  297.             putAddresses(socket, buf);
  298.         }
  299.  
  300.         continue;
  301.         }
  302.     
  303.         more = fgets(buf, sizeof(buf), fd) != 0;
  304.     }
  305.     }
  306.  
  307.     /* Send the DATA command and the mail message line by line. */
  308.     SockPuts(socket, "DATA");
  309.     if (!getSmtpReply(socket, "354")) {
  310.     return 0;
  311.     }
  312.  
  313.     fseek(fd, offset, SEEK_SET);
  314.     count = bytes;
  315.     while (fgets(buf, sizeof(buf), fd) && count > 0) {
  316.     count -= strlen(buf);
  317.     if ((s = strchr(buf, '\n')) != NULL)
  318.         *s = '\0';
  319.     if (buf[0] == '.') {
  320.         SockWrite(socket, buf, 1);    /* write an extra . */
  321.     }
  322.     SockPrintf(socket, "%s\r\n", buf);
  323.     }
  324.     fseek(fd, offset+bytes, SEEK_SET);
  325.  
  326.     SockPuts(socket, ".");
  327.     getSmtpReply(socket, "250");
  328.  
  329.     return 1;
  330. }
  331.